﻿using System;
using System.Collections.Generic;
using System.Text;
using PostSharp.Aspects.Dependencies;

namespace Arcana.Contract.Argument.Has
{
    /// <summary>
    /// Represents a contract that adheres to <b>Argument Has Any</b> semantic.
    /// </summary>
    [Serializable]
    [ProvideAspectRole(Roles.Contract)]
    [ProvideAspectRole(Roles.Method)]
    [ProvideAspectRole(Roles.Argument)]
    [ProvideAspectRole(Roles.Conditional)]
    [AspectRoleDependency(AspectDependencyAction.Commute, Roles.Conditional)]
    public sealed class AnyAttribute : ComparingContractBase
    {
        private object[] _collection;

        /// <summary>
        /// Initializes a new instance of <b>Argument.Has.AnyAttribute</b>.
        /// </summary>
        /// <remarks>
        /// <b>Note: </b>The target argument must be of type <see cref="System.Collection.IEnumerable"/>. Otherwise
        /// <see cref="System.ArgumentException"/> is thrown in validation time.
        /// </remarks>
        /// <param name="argumentName">The argument to which this contract applies.</param>
        /// <param name="collection">The array which one of it's items must be found in <i>argumentName</i>.</param>
        /// <exception cref="System.ArgumentNullException"><i>argumentName</i> or <i>collection</i> are <b>null</b>.</exception>
        public AnyAttribute(string argumentName, object[] collection)
            : base(argumentName)
        {
            if (collection == null) throw new ArgumentNullException();
            _collection = collection;
        }

        /// <summary>
        /// Performs validation on the argument.
        /// </summary>
        /// <remarks>
        /// <b>Note: </b>The target argument must be of type <see cref="System.Collection.IEnumerable"/>. Otherwise
        /// <see cref="System.ArgumentException"/> is thrown in validation time.
        /// </remarks>
        /// <param name="argument">The argument that should be validated.</param>
        /// <returns><b>true</b> if <i>argument</i> is validated, otherwise <b>false</b>.</returns>
        protected override bool ValidateArgument(object argument)
        {
            var _argument = argument as System.Collections.IEnumerable;
            if (_argument == null) throw new ArgumentException();
            if (_collection.Length == 0) return true;
            foreach (var argumentItem in _argument)
            {
                foreach (var collectionItem in _collection)
                {
                    if (Comparer.Compare(argumentItem, collectionItem) == 0) return true;
                }
            }
            return false;
        }
    }
}
